#include "documentpage.h"

DocumentPage::DocumentPage(QWidget *parent) : QLabel(parent) {
	clickMode=None;
	currentScale=1.0;
	rubberBand=0;

	actionDelete=new QAction(tr("Delete note"), this);
	connect(actionDelete, SIGNAL(triggered()), this, SLOT(deleteTriggered()));
	actionChangeText=new QAction(tr("Change note text"), this);
	connect(actionChangeText, SIGNAL(triggered()), this, SLOT(changeTextTriggered()));
	actionDrawText=new QAction(tr("Redraw note text"), this);
	connect(actionDrawText, SIGNAL(triggered()), this, SLOT(drawTriggered()));
	actionCancelDraw=new QAction(tr("Don't print note"), this);
	connect(actionCancelDraw, SIGNAL(triggered()), this, SLOT(dontDrawTriggered()));


	setMouseTracking(true);
	setAttribute(Qt::WA_StaticContents);
}

DocumentPage::~DocumentPage() {
}

void DocumentPage::addTextNote(bool add) {
	if (add) clickMode=TextNoteMode;
	else clickMode=None;
}

void DocumentPage::addRectNote(bool add) {
	if (add) clickMode=RectNoteMode;
	else clickMode=None;
}

void DocumentPage::getSelection(bool get) {
	if (get) clickMode=SelectMode;
	else clickMode=None;
}

void DocumentPage::selectAll() {
	clickMode=SelectMode;
	selectedArea(pixmap()->rect());
}

void DocumentPage::mousePressEvent(QMouseEvent *event) {
	if (event->button()!=Qt::LeftButton) return;
	QPoint point(event->x(), event->y());

	if (clickMode==TextNoteMode) {
		createTextNote(point);
		clickMode=None;
	} else if (clickMode==SelectMode || clickMode==RectNoteMode || clickMode==DrawMode){
	    dragPosition = event->pos();
	    if (!rubberBand)
	        rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
	    rubberBand->setGeometry(QRect(dragPosition, QSize()));
	    rubberBand->show();
	} else if (clickMode==None) {
		int index = itemAt(point);
		if (index!=-1)
			NotesDialog::showNote(this, tr("Note"), clickPoints[index].text());
	}
}


void DocumentPage::mouseMoveEvent(QMouseEvent *event) {
	if (!rubberBand) return;
    rubberBand->setGeometry(QRect(dragPosition, event->pos()).normalized());
}

void DocumentPage::mouseReleaseEvent(QMouseEvent *) {
	if (!rubberBand) return;
    if (!rubberBand->size().isEmpty() && pixmap()) {
        QRectF rect = QRectF(rubberBand->pos(), rubberBand->size());
        rect.moveLeft(rect.left() - (width() - pixmap()->width()) / 2.0);
        rect.moveTop(rect.top() - (height() - pixmap()->height()) / 2.0);
        if (clickMode==SelectMode) selectedArea(rect);
        else if (clickMode==RectNoteMode) createRectNote(rect);
        else if (clickMode==DrawMode) drawNoteText(rect);
    }
    rubberBand->hide();
}

void DocumentPage::contextMenuEvent(QContextMenuEvent *event) {
	int idx=itemAt(event->pos());
	if (idx!=-1) {
		contextNote=clickPoints[idx].note();
		QMenu menu(this);
		menu.addAction(actionChangeText);
		menu.addAction(actionDrawText);
		menu.addAction(actionCancelDraw);
		menu.addSeparator();
		menu.addAction(actionDelete);
		menu.exec(event->globalPos());
	}
}

void DocumentPage::deleteTriggered() {
	contextNote->invalidate();
	emit notesChanged();
}

void DocumentPage::changeTextTriggered() {
	bool ok;
	QString text=NotesDialog::getNoteText(this, tr("Change Note"), tr("Input the note text:"), contextNote->text(), &ok);

	if (ok) {
		contextNote->setText(text);
		contextNote->setDrawRect(QRectF());
		emit notesChanged();
	}
}

void DocumentPage::drawTriggered() {
	clickMode=DrawMode;
	setCursor(Qt::CrossCursor);
}

void DocumentPage::dontDrawTriggered() {
	contextNote->setDrawRect(QRectF());
	clickMode=None;
	emit notesChanged();
}

void DocumentPage::drawNoteText(QRectF rect) {
	contextNote->setDrawRect(QRectF(rect.topLeft()/currentScale, rect.size()/currentScale));
	clickMode=None;
	setCursor(Qt::ArrowCursor);
	emit notesChanged();
}

void DocumentPage::createTextNote(QPointF point) {
	bool ok;
	QString text=NotesDialog::getNoteText(this, tr("Add Note"), tr("Input the note text:"), QString::null, &ok);

	if (ok && !text.isEmpty()) {
		TextNote note(currentPage, point/currentScale, text);
		emit textNoteAdded(&note);
	}
}

void DocumentPage::createRectNote(QRectF rect) {
	bool ok;
	QString text=NotesDialog::getNoteText(this, tr("Add Note"), tr("Input the note text:"), QString::null, &ok);

	if (ok) {
		QPointF p=rect.topLeft();
		RectNote note(currentPage, QRectF(rect.topLeft()/currentScale, rect.size()/currentScale), text);
		emit rectNoteAdded(&note);
	}
}

void DocumentPage::selectedArea(const QRectF &rect) {
	QRectF selectedRect = matrix().inverted().mapRect(rect);
	if (clickMode==SelectMode) emit areaSelected(selectedRect);
}


void DocumentPage::setImg(QImage img) {
    if (!searchLocation.isEmpty()) {
        QRect highlightRect = matrix().mapRect(searchLocation).toRect();
        highlightRect.adjust(-2, -2, 2, 2);
        QImage highlight = img.copy(highlightRect);
        QPainter painter;
        painter.begin(&highlight);
        painter.fillRect(highlight.rect(), QColor(0, 0, 127, 64));
        painter.end();
        painter.begin(&img);
        painter.drawImage(highlightRect, highlight);
        painter.end();
    }

    clickPoints.clear();

    if (!notes->textNotes().isEmpty()) {
    	QList<TextNote> &textNotes=notes->textNotes();
    	for (int i=0; i<textNotes.count(); i++) {
    		clickPoints.append(ClickPoint(&textNotes[i]));
    	}
    }

    QSettings settings;
    if (!notes->rectNotes().isEmpty()) {
    	QList<RectNote> &rectNotes=notes->rectNotes();
    	QPainter painter;
    	painter.begin(&img);
    	painter.setPen(settings.value("rectColor").value<QColor>());
    	for (int i=0; i<rectNotes.count(); i++) {
    		RectNote *note=&rectNotes[i];
    		if (!note->valid()) continue;
    		if (!note->text().isEmpty()) clickPoints.append(ClickPoint(note));
    		painter.drawRect(QRectF(note->rectangle().topLeft()*currentScale, note->rectangle().size()*currentScale));
    	}
    	painter.end();
    }

    if (!clickPoints.isEmpty()) {
    	bool ok;
    	QPainter painter;
    	painter.begin(&img);
    	painter.setPen(settings.value("textColor").value<QColor>());

    	QFont font = settings.value("textFont", painter.font()).value<QFont>();
    	font.setPointSize((int) settings.value("fontSize", 9).toInt(&ok)*currentScale);
    	if (ok) painter.setFont(font);

    	bool icon=settings.value("noteIcon", true).toBool();
    	QImage image(":/images/note-small.png");

    	for (int i=0; i<clickPoints.count(); i++) {
    		ClickPoint point=clickPoints.at(i);
    		if (!point.note()->valid()) continue;

    		if (icon) {
    			painter.drawImage(point.point()*currentScale, image);
    		} else {
    			int iconS=IconSize;
    			qreal size=qMin((double) iconS, iconS*currentScale);
    			painter.fillRect(QRectF(point.point()*currentScale, QSize(size, size)), settings.value("clickPointColor").value<QColor>());
    		}

    		QRectF rect;
    		if (point.note()->drawRect().isEmpty()) {
    			QFontMetrics fm=painter.fontMetrics();
    			rect=findPrintRect(fm, point.point(), point.note()->text());
    		} else {
    			rect=point.note()->drawRect();
    		}
    		QRectF drawRect(rect.topLeft()*currentScale, rect.size()*currentScale);
    		painter.drawText(drawRect, point.note()->text());
    	}
    	painter.end();
    }

    setPixmap(QPixmap::fromImage(img));
}

QMatrix DocumentPage::matrix() const {
	return QMatrix(currentScale * physicalDpiX() / 72.0, 0, 0,
				currentScale * physicalDpiY() / 72.0, 0, 0);
}

bool DocumentPage::event(QEvent *event){
    if (event->type() == QEvent::ToolTip) {
        QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
        int idx = itemAt(helpEvent->pos());
        if (idx != -1)
            QToolTip::showText(helpEvent->globalPos(), clickPoints[idx].toolTip());
        else
            QToolTip::showText(helpEvent->globalPos(), "");
    }
    return QWidget::event(event);

}

int DocumentPage::itemAt(const QPoint &pos) {
	for (int i=0; i<clickPoints.count(); i++) {
		QRectF r(clickPoints[i].point()*currentScale, QSize(IconSize, IconSize));
		if (r.contains(pos)) {
			return i;
		}
	}
    return -1;
}

QRectF DocumentPage::findPrintRect(QFontMetrics &fm, QPointF &point, QString text){
	QRectF rect = fm.boundingRect(text);
	rect.translate(point.x()+15/currentScale, point.y()+fm.height()/2);

	if (rect.right() > geometry().right()) {
		rect.moveRight(point.x());
	}
	if (rect.bottom() > geometry().bottom()) {
		rect.moveBottom(geometry().bottom());
	}
	if (rect.top() <geometry().top()) {
		rect.moveTop(geometry().top());
	}
	return rect;
}

